<!doctype html>
<html lang="en">
  <head>
    <title>faces.js - A JavaScript library for generating vector-based cartoon faces</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Arvo:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
  </head>
  <body>
    <div id="container">
      <div class="navbar">
        <h1>faces.js</h1>
        <a href="/facesjs/editor/" class="navbar-button editor">Face editor</a>
        <a href="https://github.com/zengm-games/facesjs" class="navbar-button github">
          Fork me<span class="hide-sm"> on GitHub</span>
          <svg width="25px" height="25px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
            <g transform="translate(-140.000000, -7559.000000)" fill="#000000">
              <g transform="translate(56.000000, 160.000000)">
                <path d="M94,7399 C99.523,7399 104,7403.59 104,7409.253 C104,7413.782 101.138,7417.624 97.167,7418.981 C96.66,7419.082 96.48,7418.762 96.48,7418.489 C96.48,7418.151 96.492,7417.047 96.492,7415.675 C96.492,7414.719 96.172,7414.095 95.813,7413.777 C98.04,7413.523 100.38,7412.656 100.38,7408.718 C100.38,7407.598 99.992,7406.684 99.35,7405.966 C99.454,7405.707 99.797,7404.664 99.252,7403.252 C99.252,7403.252 98.414,7402.977 96.505,7404.303 C95.706,7404.076 94.85,7403.962 94,7403.958 C93.15,7403.962 92.295,7404.076 91.497,7404.303 C89.586,7402.977 88.746,7403.252 88.746,7403.252 C88.203,7404.664 88.546,7405.707 88.649,7405.966 C88.01,7406.684 87.619,7407.598 87.619,7408.718 C87.619,7412.646 89.954,7413.526 92.175,7413.785 C91.889,7414.041 91.63,7414.493 91.54,7415.156 C90.97,7415.418 89.522,7415.871 88.63,7414.304 C88.63,7414.304 88.101,7413.319 87.097,7413.247 C87.097,7413.247 86.122,7413.234 87.029,7413.87 C87.029,7413.87 87.684,7414.185 88.139,7415.37 C88.139,7415.37 88.726,7417.2 91.508,7416.58 C91.513,7417.437 91.522,7418.245 91.522,7418.489 C91.522,7418.76 91.338,7419.077 90.839,7418.982 C86.865,7417.627 84,7413.783 84,7409.253 C84,7403.59 88.478,7399 94,7399" id="github-[#142]"></path>
              </g>
            </g>
          </svg>
        </a>
      </div>
      <h2 class="subtitle">A JavaScript library for generating vector-based cartoon faces</h2>
      <div id="faces">
        <div id="c0" class="big" onclick="javascript:newFace(0)"></div>
        <div id="c1" onclick="javascript:newFace(1)"></div>
        <div id="c2" onclick="javascript:newFace(2)"></div>
        <div id="c3" onclick="javascript:newFace(3)"></div>
        <div id="c4" onclick="javascript:newFace(4)"></div>
        <div id="c5" class="hide-sm" onclick="javascript:newFace(5)"></div>
        <div id="c6" class="hide-sm" onclick="javascript:newFace(6)"></div>
        <div id="c7" class="hide-sm" onclick="javascript:newFace(7)"></div>
        <div id="c8" class="hide-sm" onclick="javascript:newFace(8)"></div>
        <div id="c9" class="hide-sm" onclick="javascript:newFace(9)"></div>
        <div id="c10" class="hide-sm" onclick="javascript:newFace(10)"></div>
        <div id="c11" class="hide-sm" onclick="javascript:newFace(11)"></div>
      </div>
      <p style="font-style: italic; margin-top: 0.25em">
        To load new random faces, <a href="javascript:newFaces()">click here</a> or press "r" on your keyboard.
      </p>
      <p>
        faces.js is a JavaScript library that generates and displays cartoon faces, somewhat reminiscent of Nintendo's Miis. Faces are drawn as SVGs and are also represented by a small JavaScript object, which allows you to store that object and then draw the same face again later.
      </p>
      <p>
        Originally faces.js was made for <a href="https://basketball-gm.com/">Basketball GM</a> and other games by <a href="https://zengm.com/">ZenGM</a>, but now it is used in several other projects.
      </p>
      <h1>For users</h1>

      <p>You can use the <a href="/facesjs/editor/">face editor</a> to generate a custom face, and then export in JSON/SVG/PNG format.</p>
      <h1>For developers</h1>

      (This is just a copy of <a href="https://github.com/zengm-games/facesjs">the README from the GitHub repo</a>.)
    </div>
    <div id="container2">
<h2 id="installation">Installation</h2>
<pre><code>npm install --save facesjs</code></pre>
<h2 id="use">Use</h2>
<p>Import it with ES modules:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { display<span class="op">,</span> generate } <span class="im">from</span> <span class="st">&quot;facesjs&quot;</span><span class="op">;</span></span></code></pre></div>
<p>or CommonJS:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> { display<span class="op">,</span> generate } <span class="op">=</span> <span class="pp">require</span>(<span class="st">&quot;facesjs&quot;</span>)<span class="op">;</span></span></code></pre></div>
<p>Then, generate a random face:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> face <span class="op">=</span> <span class="fu">generate</span>()<span class="op">;</span></span></code></pre></div>
<p>And display it:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Display in a div with id &quot;my-div-id&quot;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(<span class="st">&quot;my-div-id&quot;</span><span class="op">,</span> face)<span class="op">;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co">// Display in a div you already have a reference to</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> element <span class="op">=</span> <span class="bu">document</span><span class="op">.</span><span class="fu">getElementById</span>(<span class="st">&quot;my-div-id&quot;</span>)<span class="op">;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(element<span class="op">,</span> face)<span class="op">;</span></span></code></pre></div>
<p>If you’d like a non-random face, look inside the <code>face</code>
variable and you’ll see all the available options for a manually
constructed face.</p>
<h3 id="overrides">Overrides</h3>
<p>Both <code>display</code> and <code>generate</code> accept an
optional argument, specifying values to override either the randomly
generated face (for <code>generate</code>) or the supplied face (for
<code>display</code>). For instance:</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Generate a random face that always has blue skin</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> face <span class="op">=</span> <span class="fu">generate</span>({ <span class="dt">body</span><span class="op">:</span> { <span class="dt">color</span><span class="op">:</span> <span class="st">&quot;blue&quot;</span> } })<span class="op">;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co">// Display a face, but impose that it has blue skin</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(<span class="st">&quot;my-div-id&quot;</span><span class="op">,</span> face<span class="op">,</span> { <span class="dt">body</span><span class="op">:</span> { <span class="dt">color</span><span class="op">:</span> <span class="st">&quot;blue&quot;</span> } })<span class="op">;</span></span></code></pre></div>
<h3 id="options">Options</h3>
<p>The <code>generate</code> function takes a second optional argument,
which takes in extra parameters for player creation, in the form of an
object.</p>
<p>Generate a female/male face (default is male):</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> face <span class="op">=</span> <span class="fu">generate</span>(<span class="kw">undefined</span><span class="op">,</span> { <span class="dt">gender</span><span class="op">:</span> <span class="st">&quot;female&quot;</span> })<span class="op">;</span></span></code></pre></div>
<p>Assign a race attribute that can be white, black, asian, or brown
(default is random):</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> face <span class="op">=</span> <span class="fu">generate</span>(<span class="kw">undefined</span><span class="op">,</span> { <span class="dt">race</span><span class="op">:</span> <span class="st">&quot;white&quot;</span> })<span class="op">;</span></span></code></pre></div>
<p>Or both together:</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> face <span class="op">=</span> <span class="fu">generate</span>(<span class="kw">undefined</span><span class="op">,</span> { <span class="dt">gender</span><span class="op">:</span> <span class="st">&quot;female&quot;</span><span class="op">,</span> <span class="dt">race</span><span class="op">:</span> <span class="st">&quot;asian&quot;</span> })<span class="op">;</span></span></code></pre></div>
<p>There is also an option to create a relative of an existing face
object. This works by randomizing only some features of the existing
face, so the new face is fairly similar to the existing one, like an
immediate family member.</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> face1 <span class="op">=</span> <span class="fu">generate</span>()<span class="op">;</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> face2 <span class="op">=</span> <span class="fu">generate</span>(<span class="kw">undefined</span><span class="op">,</span> { <span class="dt">gender</span><span class="op">:</span> <span class="st">&quot;female&quot;</span><span class="op">,</span> <span class="dt">relative</span><span class="op">:</span> face1 })<span class="op">;</span></span></code></pre></div>
<h3 id="react-integration">React integration</h3>
<p>You can use the <code>display</code> function within any frontend JS
framework, but for ease of use with the most popular one, this package
includes a <code>Face</code> component for React.</p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { generate } <span class="im">from</span> <span class="st">&quot;facesjs&quot;</span><span class="op">;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { Face } <span class="im">from</span> <span class="st">&quot;facesjs/react&quot;</span><span class="op">;</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { useEffect } <span class="im">from</span> <span class="st">&quot;react&quot;</span><span class="op">;</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">const</span> MyFace <span class="op">=</span> ({ face }) <span class="kw">=&gt;</span> {</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">&lt;</span>Face</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>        face<span class="op">=</span>{face}</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>        lazy</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>        style<span class="op">=</span>{{</span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>            <span class="dt">width</span><span class="op">:</span> <span class="dv">100</span><span class="op">,</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>        }}</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;;</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>}<span class="op">;</span></span></code></pre></div>
<p>Props of the <code>Face</code> component:</p>
<table>
<colgroup>
<col style="width: 20%" />
<col style="width: 20%" />
<col style="width: 20%" />
<col style="width: 20%" />
<col style="width: 20%" />
</colgroup>
<thead>
<tr class="header">
<th>Prop</th>
<th>Required</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>face</code></td>
<td>Y</td>
<td><code>FaceConfig</code></td>
<td></td>
<td>Face object, output of <code>generate</code>.</td>
</tr>
<tr class="even">
<td><code>overrides</code></td>
<td></td>
<td><code>Overrides</code></td>
<td></td>
<td>Optional overrides object, as described above.</td>
</tr>
<tr class="odd">
<td><code>ignoreDisplayErrors</code></td>
<td></td>
<td><code>boolean</code></td>
<td><code>false</code></td>
<td>If <code>true</code>, then any errors when internally running
<code>display</code> will be suppressed. This is useful if you accept
user-defined faces and you don’t want errors from them to clog up your
error logs.</td>
</tr>
<tr class="even">
<td><code>lazy</code></td>
<td></td>
<td><code>boolean</code></td>
<td><code>false</code></td>
<td>If <code>true</code>, then application of overrides and rendering of
the face will be delayed until this component is actually visible (as
determined by an intersection observer).</td>
</tr>
<tr class="odd">
<td><code>className</code></td>
<td></td>
<td><code>string</code></td>
<td></td>
<td>If provided, will be put on the wrapper div.</td>
</tr>
<tr class="even">
<td><code>style</code></td>
<td></td>
<td><code>CSSProperties</code></td>
<td></td>
<td>If provided, will be put on the wrapper div.</td>
</tr>
</tbody>
</table>
<h2 id="exporting-svgs">Exporting SVGs</h2>
<h3 id="api">API</h3>
<p>You can use <code>faceToSvgString</code> to convert a face object to
an SVG string.</p>
<div class="sourceCode" id="cb12"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { faceToSvgString<span class="op">,</span> generate } <span class="im">from</span> <span class="st">&quot;facesjs&quot;</span><span class="op">;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> face <span class="op">=</span> <span class="fu">generate</span>()<span class="op">;</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> svg <span class="op">=</span> <span class="fu">faceToSvgString</span>(face)<span class="op">;</span></span></code></pre></div>
<p>You can also specify overrides, similar to <code>display</code>:</p>
<div class="sourceCode" id="cb13"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> svg <span class="op">=</span> <span class="fu">faceToSvgString</span>(face<span class="op">,</span> { <span class="dt">body</span><span class="op">:</span> { <span class="dt">color</span><span class="op">:</span> <span class="st">&quot;blue&quot;</span> } })<span class="op">;</span></span></code></pre></div>
<p><code>faceToSvgString</code> is intended to be used in Node.js If you
are doing client-side JS, it would be more efficient to render a face to
the DOM using <code>display</code> and then <a
href="https://github.com/zengm-games/facesjs/blob/19ce236af6adbf76db29c4e669210b30e1de0e1a/public/editor/downloadFace.ts#L61-L64">convert
it to a blob like this</a>.</p>
<h3 id="cli">CLI</h3>
<p>You can also use <code>facesjs</code> as a CLI program. All of the
functionality from <code>generate</code> and <code>display</code> are
available on the CLI too.</p>
<h4 id="examples">Examples</h4>
<p>Output a random face to stdout:</p>
<pre><code>$ npx facesjs</code></pre>
<p>Generate a blue female face and output to stdout:</p>
<pre><code>$ npx facesjs -j &#39;{&quot;body&quot;:{&quot;color&quot;:&quot;blue&quot;}}&#39; -g female</code></pre>
<p>Generate a male white face and save it to test.svg:</p>
<pre><code>$ npx facesjs -r white -o test.svg</code></pre>
<h4 id="options-1">Options</h4>
<pre><code>-h, --help          Prints this help
-o, --output        Output filename to use rather than stdout
-f, --input-file    Path to a faces.js JSON file to convert to SVG
-j, --input-json    String faces.js JSON object to convert to SVG
-r, --race          Race - white/black/asian/brown, default is random
-g, --gender        Gender - male/female, default is male</code></pre>
<p><code>--input-file</code> and <code>--input-json</code> can specify
either an entire face object or a partial face object. If it’s a partial
face object, the other features will be random.</p>
<h2 id="development">Development</h2>
<p>Running <code>pnpm run dev</code> will do a few things:</p>
<ol type="1">
<li>Give you a URL to open the face editor UI in your browser</li>
<li>Watch for changes to the code</li>
<li>Watch for changes to the facial feature SVG files</li>
<li>Update the face editor UI when any code or SVG changes</li>
</ol>
<p>This lets you immediately see your changes as you work.</p>
<h2 id="adding-new-facial-features">Adding new facial features</h2>
<p>Each face is assembled from multiple SVGs. You can see them within
the “svg” folder. If you want to add another feature, just create an SVG
(using a vector graphics editor like <a
href="https://inkscape.org/">Inkscape</a>) and put it in the appropriate
folder. It should automatically work. If not, it’s a bug, please let me
know!</p>
<p>When creating SVGs, assume the size of the canvas is 400x600. For
most features, it doesn’t matter where you draw on the canvas because it
will automatically identify your object and position it in the
appropriate place. But for head and hair SVGs, position does matter. For
those you do need to make sure they are in the correct place on a
400x600 canvas, same as the existing head and hair SVGs. Otherwise it
won’t know where to place the other facial features relative to the head
and hair.</p>
<p>If you find it not quite placing a facial feature exactly where you
want, it’s because by default it finds the center of the
eye/eyebrow/mouth/nose SVG and places that in a specific location. If
that’s not good for a certain facial feature, that behavior can be
overridden in code. For instance, see how it’s done in display.js for
the “pinocchio” nose which uses the left side of the SVG rather than the
center to place it.</p>
<p>If you want a brand new “class” of facial features (like facial hair,
or earrings, or hats) you’ll have to create a new subfolder within the
“svg” folder and edit the code to recognize your new feature.</p>
<p>If you find any of this confusing, feel free to reach out to me for
help! I would love for someone to help me make better looking faces
:)</p>
<h2 id="credits">Credits</h2>
<p><a href="https://github.com/dumbmatter">dumbmatter</a> wrote most of
the code, <a href="https://github.com/TravisJB89">TravisJB89</a> made
most of the graphics, <a href="https://liacui.carrd.co/">Lia Cui</a>
made most of the female graphics, <a
href="https://github.com/gurushida">gurushida</a> wrote the code to
export faces as SVG strings, and <a
href="https://github.com/tomkennedy22">tomkennedy22</a> wrote most of
the editor UI code.</p>
    </div>
    <script type="module" src="index.ts"></script>
  </body>
</html>
